﻿#pragma once





#include <assert.h>
#include <math.h>
#include <cmath>
#include <string>
#include <vector>

using namespace std; 

//
//#ifndef	min
//#define	min(a, b)	((a) < (b) ? (a) : (b))
//#endif
//
//#ifndef max
//#define	max(a, b)	((a) > (b) ? (a) : (b))
//#endif


class XCollector  
{
private:
	char * m_pbuff ;
	int    m_head  ;
	int	   m_tail  ;
	int	   m_upbound ;
	int	   m_max_len ;  
	int	   m_auto_free_size;
	  
public:
  
	const char * GetData() const { return &m_pbuff[m_head] ; }
	int	  GetSize() const { return m_tail-m_head ; }

	int	  GetBound() const { return m_upbound ; }
	 
	XCollector() {
		m_pbuff = NULL; 
		m_head	= 0 ;
		m_tail  = 0 ;
		m_upbound = 0 ;
		m_max_len = -1 ;
	 
		m_auto_free_size = 20000 ; 
									 
	}
	
	XCollector( const XCollector & src) {
		m_pbuff = NULL ; 
		m_head	= 0 ;
		m_tail  = 0 ;
		m_upbound = 0 ;
		m_max_len = -1 ;
		m_auto_free_size = 20000 ;  
		*this = src ;
	}

	~XCollector() {
		if( m_pbuff ){
			delete m_pbuff ;
		}
	}

	void	SetAutoFreeSize( int size ) {
			assert( size > 0 ) ;
			m_auto_free_size = size ;
			if( m_max_len == -1 && GetSize() == 0 && m_upbound > m_auto_free_size ){
				Free();
				PreBuffer( 256 ) ;
				m_head = 0 ;
				m_tail = 0 ;
			}
	}

	void	SetMaxBuffLength( int max ){
		m_max_len = max ;
		if( m_max_len != -1 ){
 		
 			char * p = new char[ m_max_len ] ;
			memset(p, 0, m_max_len );
			m_upbound = m_max_len ;
 
			if( m_pbuff ){
				int size = min( GetSize(), m_max_len) ;
				memcpy( p, GetData(), size ) ;
				delete m_pbuff ;
				m_tail = size ;
			}
			else{
				m_tail = 0 ;
			}

			m_pbuff = p ;
			m_head =  0;
		}
	}

	void	RemoveAll(){
		SetSize(0);
	}

	int	TrimLeft( int len )
	{
		if( len <= 0 ) return 0;
		len = min( len , GetSize() ) ;
 
		if( !m_pbuff ) { assert(0); return 0;}

		m_head += len ;
		
		if( m_head == m_tail ){
			m_head = 0 ;
			m_tail = 0 ;
		}

		return len ;
	}

	int TrimRight( int len )
	{
		if( len<=0 ) return 0;
		len = min( len , GetSize() );

		if( !m_pbuff ){ assert(0);return 0;}

		m_tail -= len ;

		if( m_head == m_tail ){
			m_head = 0 ;
			m_tail = 0 ;
		}


		return len;
	}

	int	Pop2(  void * rbuff, int len ){
		if( len == 0 ) return 0 ;

 		len = min( GetSize(), len );

		if( !m_pbuff ) { assert(0); return 0;}
	
		char * buff = (char*)rbuff;
		char * src  = (char*)GetData();
		if( len <= 8 ){
			for( int ii = 0 ; ii < len ; ii ++ ){
				buff[ii] = src[ii] ;
			}
		}
		else{
 			memcpy( buff, GetData(), len );
		}
		m_head += len ;
 		return len ;
	}


	bool   Pop( void * rbuff, int len ) {
		if( len == 0 ) return true ; 

		if( len > GetSize() ) return false;

		if( !m_pbuff ) { assert(0); return false;}

		char * buff = (char*)rbuff;
 		char * src  = (char*)GetData();
		if( len <= 8 ){
			for( int ii = 0 ; ii < len ; ii ++ ){
				buff[ii] = src[ii] ;
			}
		}
		else{
 			memcpy( buff, GetData(), len );
		}

		m_head += len ;
 		return true ;
	}

	bool   Popchar( char & val ){
			return Pop( &val, sizeof( val ) ) ;
	}

	bool   Popbool( bool & val  ){
			return Pop( &val, sizeof( val ) ) ;
	}

	bool   PopShort( short & val ){
			return	Pop( &val, sizeof( val ) ) ;
	}

	bool   PopInt32( int & val   ){
			return Pop( &val, sizeof( val ) ) ;
	}

	bool   PopInt64( long long & val   ){
			return Pop( &val, sizeof( val ) ) ;
	}

	bool   PopFloat( float & val  ){
			return Pop( &val, sizeof(val) );
	}

	bool   PopString( string & str ){
		int vv  ;
		if( !Pop( (char*) &vv, sizeof( int) )  ) return false ;
	
		if( vv > 0 ){
			if( vv > GetSize() ){
				assert(0);
				RemoveAll();
				str.clear();
				return false ;
			}
			assert( vv < 9999999 ) ;
			//LPTSTR p = str.GetBufferSetLength( vv ) ;
			char * p = new char[vv];
			memset(p, 0, vv);
			bool bb = Pop( p, vv ) ; 
			if( bb ) {
				str = p;
			}
			delete [] p;
			p = NULL;
			return bb;
		}
		else{
			str.clear();
			return true ;
		}
	} 
	
	template <class TYPE >
	bool   PopArray(std::vector< TYPE > & ary  ){
		int size =0  ;
		if( !Pop( &size, sizeof(size)  ) ) return false ;
		if( size < 0 ) {
			assert(0);
			return false ; //  || size > 99900000 
		}
		assert(  size < 999000000 ); //
	 	ary.SetSize( size ) ;
		return Pop( (char*)ary.Data(), size*sizeof(TYPE) ) ;
	}
	 

	bool   PopStringArray( std::vector<string> & ary  ){
		int size = 0 ;
		if( !Pop( &size, sizeof(size) ) ) return false ;
		if( size < 0  ){  
			assert(0);
			return false ;
		}
		assert(  size < 999000000 ); //
		ary.resize( size ) ;
		for( int i = 0 ; i < size ; i ++ ){
		   if( !PopString(  ary[i] ) ) return false ;
		}
		return true; 
	}

	bool   PopXIntArray(  std::vector<int> & ary ){
		int size ;
		if( !PopInt32( size ) || size < 0 ){  
			assert(0);
			return false ;
		}
		assert(  size < 999000000 ); //
		ary.resize( size ) ;
		return Pop( (char*)ary.data(), size * sizeof( int ) ) ;
	}


	bool   PopCollector( XCollector & ary ){
		int size = 0 ;
		if( !Pop( &size, sizeof(size) ) ) return false ;
		if( size < 0 ) { 
			assert(0);
			return false ;
		}
		assert(  size < 999000000 ); //
		ary.SetSize( size ) ;
		return Pop( (char*)ary.GetData(), size  ) ;
	}
  
	 

	void   Appendchar( char val ){
			 Append( &val, sizeof( val ) );
	}

	void   AppendShort( short val ){
 		    Append( &val, sizeof( val ) ) ;
	}

	void   Appendbool( bool val ){
			Append( &val, sizeof( val ) ) ;
	}

	void  AppendInt32( int val ) {
		     Append( &val, sizeof(val) );
	}
	void  AppendInt64( long long  val ) {
		     Append( &val, sizeof(val) );
	}

	void  AppendFloat( float val ){
			 Append( &val, sizeof(val) );
	}

	void  AppendDouble( double val ){
		Append( &val, sizeof(val) );
	}

	void   AppendString( string str) {
		if( str.empty() ) return ;
		int vv = str.length();
		AppendInt32( vv ) ;
		if( vv > 0 ){
			Append( str.c_str(), vv ) ;
		}
	}

 	void   Append( const void * buff, int len ) {
 
		if( len == 0 ) return  ;
		
		assert( len >=0 ) ;
		
		// move to head
		if( m_head > 0 ){
			if( GetSize() > 0 ){
				memcpy( m_pbuff, &m_pbuff[m_head], GetSize() );
			}
			m_tail -= m_head ;
			m_head = 0 ;
		}

		if( m_upbound < GetSize() + len )
		{
			if( m_max_len != -1 ){ // Collect ̶￿
				if( len >= m_upbound ){
					char * ppp = (char*)buff;
					memcpy( m_pbuff,  &ppp[len-m_upbound], m_upbound ) ;
					m_tail = m_upbound ;
				}
				else{
					int over_len = GetSize() + len  - m_upbound ;
					TrimLeft( over_len ) ;
					Append( buff, len );
				}
				return  ;
			}
			else{
				m_upbound =  GetSize() + len + ( GetSize() + len ) / 4  ;
				m_upbound = max( m_upbound, 256 ) ;		 
			
				if( m_upbound > m_auto_free_size && GetSize() + len <=  m_auto_free_size ){
					m_upbound = m_auto_free_size ;
				}

				char * new_p = new char[ m_upbound ] ;
				memset(new_p, 0, m_upbound);
				if( m_pbuff )
				{
					memcpy( new_p, m_pbuff, GetSize() ) ;
					delete m_pbuff ;
				}
 				m_pbuff = new_p ;
			}
		}
	
		assert( m_pbuff ) ;
		if( len <= 8 ){
			char * pppp = (char*)buff;
 			for( int ii = 0; ii < len ; ii ++ ){
				m_pbuff[m_tail+ii] =  pppp[ii] ;
			}
		}
		else{
			memcpy( &m_pbuff[m_tail], buff, len ) ;
		}
		
 		m_tail += len ;
	}
	 
	 

	void   AppendStringArray( std::vector<string> & ary ){
		AppendInt32( ary.size() ) ;
		for( int i = 0 ; i < ary.size() ; i ++ ){
			AppendString( ary[i]) ;
		}
	}
	 

	void   AppendXIntArray( const std::vector<int> & ary ){
		AppendInt32( ary.size() ) ;
		Append( (char*)ary.data(), ary.size() * sizeof( int )  ) ;
	}

	void   AppendXInt64Array( const std::vector<long long> & ary ){
		AppendInt32( ary.size() ) ;
		Append( (char*)ary.data(), ary.size() * sizeof( long long )  ) ;
	}

	void   AppendCollector(const XCollector & ary ){
		AppendInt32( ary.GetSize() ) ;
		Append( ary.GetData(), ary.GetSize() ) ; 
	}

	 
	void   PreBuffer( int size )
	{
		if( size <= 0 ) return ;
		if( m_upbound >= size ) return ;

		if( m_max_len != -1 ){  
			assert(0);
			if( m_pbuff == NULL){
				m_pbuff = new char[m_max_len] ;
				memset(m_pbuff, 0, m_max_len);
			}
			m_upbound = m_max_len ;
			m_head = 0 ;
			m_tail = 0 ;
		}
		else{
			char * np = new char[size] ;
			memset(np, 0, size);
			if( m_pbuff ){
				if( m_tail > m_head ){
					memcpy( np, &m_pbuff[m_head], m_tail - m_head ) ;
				}
				delete m_pbuff ;
			}

			m_pbuff = np ;
			m_upbound = size ;
 			m_tail = m_tail - m_head ;
			m_head = 0 ;
		}
	}
	 
	void   Free()
	{
 		if( m_pbuff ) {
			delete m_pbuff;
		}
		m_pbuff   = NULL;
		m_upbound = 0 ;
		m_head	  = 0 ;
		m_tail    = 0 ;
	} 

	void   SetSize( int len, bool bAutoFree = true  ){
		if( m_head > 0 ){
			if( m_head == m_tail ){
				m_head = 0 ;
				m_tail = 0 ;
			}
			else{
				memcpy( m_pbuff, &m_pbuff[m_head], GetSize() );
				m_tail -= m_head ;
				m_head = 0 ;
			}
		}

  		if( len <= m_upbound ){
			if( len == 0 && m_max_len == -1 && bAutoFree && m_upbound > m_auto_free_size  ){
				delete m_pbuff ;
				m_pbuff = NULL ;
				m_head  = 0 ;
				m_tail = 0;
				m_upbound= 0;
			}
			else{
 				m_tail = len ;
			}
		}
		else{
			if( m_max_len != -1 ){
				assert( m_upbound == m_max_len ) ;
				m_tail = min( m_max_len , len);
			}
			else{
				m_upbound =  max( 256, (int)( len * 1.2 ) );
				if( m_upbound > m_auto_free_size && len <=  m_auto_free_size ){
					m_upbound = m_auto_free_size ;
				}
 
				char * new_p = new char[ m_upbound ] ;
				memset(new_p, 0, m_upbound );
				if( m_pbuff ){
					memcpy( new_p, m_pbuff, GetSize() ) ;
					delete m_pbuff ;
				} 
				m_pbuff = new_p ;
				m_tail = len ;
			}
		} 
	}
   


	char & operator [] ( int ii ){
		assert( ii >= 0 && ii < GetSize() ) ;
		return (char &)m_pbuff[m_head + ii] ;
	}

	bool operator == ( const XCollector & src){
		if( src.GetSize() != GetSize() ) return false ;
		return memcmp( src.GetData(), GetData(), GetSize() ) == 0 ;
	}
	bool operator !=( const XCollector & src){
		return !( *this == src ) ;
	}
	 
	 

	void operator = ( const XCollector & src ){
		RemoveAll() ;
		if( src.m_max_len != -1 ){
			SetMaxBuffLength(src.m_max_len );
		}
		Append( src.GetData(), src.GetSize() ) ;
	 
		m_auto_free_size = src.m_auto_free_size ;  
	}
	 

public: 
	 
  
	XCollector & operator << (  int & vv ){ // 增加&，是防止自动的类型装￿但不可加const,
		                                     // 否则编译器会￿ 优化￿出现乱匹￿
 		Append( &vv, sizeof( vv ) ) ;
		return *this ;
	}

	XCollector & operator << (  char & vv ){
		Append( &vv, sizeof( vv ) ) ;
		return *this ;
	}

	XCollector & operator << (  short & vv ){
		Append( &vv, sizeof( vv ) ) ;
		return *this ;
	}

	
	XCollector & operator << ( unsigned short & vv ){
		Append( &vv, sizeof( vv ) ) ;

		return *this ;
	}

	XCollector & operator << (  long long & vv ){
		Append( &vv, sizeof( vv ) ) ;
		return *this ;
	}

  		
	XCollector & operator << (  float & vv ){
		Append( &vv, sizeof( vv ) ) ;
		return *this ;
	}	
	XCollector & operator << (  double & vv ){
		Append( &vv, sizeof( vv ) ) ;
		return *this ;
	}


	XCollector & operator << ( const string & vv ){
		AppendString( vv ) ;
		return *this ;
	} 
	 
	void Write( void * pBuff, int size )
	{
		Append( pBuff, size ) ;
	}

	
 	XCollector & operator >> ( char & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}

 	XCollector & operator >> ( int & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}

	XCollector & operator >> ( short & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}


	XCollector & operator >> ( unsigned  short & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}


	XCollector & operator >> ( long long & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}

	
	XCollector & operator >> ( float & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}
		
	XCollector & operator >> ( double & vv ){
		Pop( &vv, sizeof( vv ) ) ;
		return *this ;
	}

	XCollector & operator >> ( string & vv ){
		PopString( vv ) ;
		return *this ;
	} 

	bool Read( void * pBuff, long size )
	{
		return Pop( pBuff, size ) ;
	}
 
};